package view;

import model.DrawableVertex;
import model.DrawableGraph;
import java.util.List;
import java.util.Random;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import model.DjikstraAlgorithm;
import model.DrawableEdge;
import model.DrawableRoute;
import model.Edge;
import model.Graph;
import model.Route;
import model.Vertex;

/**
 * <p>
 * Title: RouteViewGUI</p>
 * <p>
 * Description: CS 343 Project. An implementation of a visual graph.</p>
 *
 * @date 11/18/2013
 *
 * @author Dylan Ahmann
 * @author Gregg Roemhildt
 * @author Sam Brockmann
 * @author Emily Hancock
 * @author Shirin Asadi
 *
 */
public class RouteViewGUI extends JFrame {

    private Graph<double[]> graph;
    private Route<double[]> route;
    private final int OFFSET = 100;
    private final int SIZE = 10;
    private final DefaultComboBoxModel fromSelection;
    private final DefaultComboBoxModel toSelection;
    private double offsetX, offsetY;
    private int dragStartX, dragStartY;

    /**
     * Creates new form RouteViewGUI
     */
    public RouteViewGUI() {

        //set up graph
        graph = new DrawableGraph();
        Random generator = new Random();
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                double[] x = {i * OFFSET + generator.nextInt(50),
                    j * OFFSET + generator.nextInt(50)};
                Vertex v = new DrawableVertex(x, "point " + (i * 10) + j);
                graph.addVertex(v);
            }
        }
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE - 1; j++) {
                Vertex v1 = graph.getVertices().get(i + SIZE * j);
                Vertex v2 = graph.getVertices().get(i + 1 + SIZE * j);
                Edge e1 = new DrawableEdge(v1, v2);
                graph.addEdge(e1);

                Vertex v3 = graph.getVertices().get(i + SIZE + SIZE * j);
                Edge e2 = new DrawableEdge(v1, v3);
                graph.addEdge(e2);
            }
        }
        fromSelection = new DefaultComboBoxModel(graph.getVertices().toArray());
        toSelection = new DefaultComboBoxModel(graph.getVertices().toArray());

        offsetX = 0;
        offsetY = 0;
        dragStartX = 0;
        dragStartY = 0;
// database testing...
//        EntityList<Graph> l = new EntityList<>("Graph");
//        l.add(graph);

        //I was working on a way to draw the background map to a different
        //panel
        //
        //-Dylan
//
//        BufferedImage background = null;
//          File mapImage = new File("src/view/BackgroundMap.jpg");
//        try {
//            background = ImageIO.read(mapImage);
//        } catch (IOException ex) {
//            Logger.getLogger(RouteViewGUI.class.getName()).log(Level.SEVERE, null, ex);
//        }
//          Graphics backgroundG = background.getGraphics();
//          map1.paint(backgroundG);
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        pnlButonTray = new javax.swing.JPanel();
        cmbPointA = new javax.swing.JComboBox();
        cmbPointB = new javax.swing.JComboBox();
        btnNavigate = new javax.swing.JButton();
        lblPointB = new javax.swing.JLabel();
        lblPointA = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        statusText = new javax.swing.JLabel();
        map1 = new Map(graph);
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        jMenu4 = new javax.swing.JMenu();
        jMenu3 = new javax.swing.JMenu();
        jMenu2 = new javax.swing.JMenu();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));

        cmbPointA.setModel(fromSelection);
        cmbPointA.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cmbPointAActionPerformed(evt);
            }
        });

        cmbPointB.setModel(toSelection);

        btnNavigate.setText("Navigate");
        btnNavigate.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnNavigateMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                btnNavigateMousePressed(evt);
            }
        });
        btnNavigate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnNavigateActionPerformed(evt);
            }
        });

        lblPointB.setText("To:");

        lblPointA.setText("From:");

        jLabel1.setText("Status:");

        statusText.setText("Ready");

        javax.swing.GroupLayout pnlButonTrayLayout = new javax.swing.GroupLayout(pnlButonTray);
        pnlButonTray.setLayout(pnlButonTrayLayout);
        pnlButonTrayLayout.setHorizontalGroup(
            pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlButonTrayLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lblPointA)
                    .addComponent(cmbPointA, 0, 296, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(cmbPointB, 0, 284, Short.MAX_VALUE)
                    .addGroup(pnlButonTrayLayout.createSequentialGroup()
                        .addComponent(lblPointB)
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(btnNavigate, javax.swing.GroupLayout.PREFERRED_SIZE, 106, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(pnlButonTrayLayout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(statusText)))
                .addContainerGap())
        );
        pnlButonTrayLayout.setVerticalGroup(
            pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlButonTrayLayout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblPointB)
                    .addComponent(lblPointA)
                    .addComponent(jLabel1)
                    .addComponent(statusText))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(pnlButonTrayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cmbPointA, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(cmbPointB, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnNavigate))
                .addContainerGap())
        );

        map1.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                map1MouseWheelMoved(evt);
            }
        });
        map1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                map1MousePressed(evt);
            }
        });
        map1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                map1MouseDragged(evt);
            }
        });

        javax.swing.GroupLayout map1Layout = new javax.swing.GroupLayout(map1);
        map1.setLayout(map1Layout);
        map1Layout.setHorizontalGroup(
            map1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 698, Short.MAX_VALUE)
        );
        map1Layout.setVerticalGroup(
            map1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 527, Short.MAX_VALUE)
        );

        jMenu1.setText("File");

        jMenu4.setText("Load");
        jMenu4.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jMenu4MouseClicked(evt);
            }
        });
        jMenu1.add(jMenu4);

        jMenu3.setText("Save");
        jMenu3.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jMenu3MouseClicked(evt);
            }
        });
        jMenu1.add(jMenu3);

        jMenuBar1.add(jMenu1);
        jMenuBar1.add(jMenu2);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(pnlButonTray, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(map1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addContainerGap()))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(0, 473, Short.MAX_VALUE)
                .addComponent(pnlButonTray, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(map1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addContainerGap()))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void btnNavigateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNavigateActionPerformed

    }//GEN-LAST:event_btnNavigateActionPerformed

    private void btnNavigateMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnNavigateMouseClicked

    }//GEN-LAST:event_btnNavigateMouseClicked

    private void cmbPointAActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbPointAActionPerformed

    }//GEN-LAST:event_cmbPointAActionPerformed

    private void btnNavigateMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnNavigateMousePressed
        final DjikstraAlgorithm dAlg = new DjikstraAlgorithm(graph);
        final Vertex from = (Vertex) fromSelection.getSelectedItem();
        final Vertex to = (Vertex) toSelection.getSelectedItem();
        dAlg.setSource(from);

        SwingWorker<Boolean, Void> worker;
        worker = new SwingWorker<Boolean, Void>() {
            @Override
            protected Boolean doInBackground() throws Exception {
                statusText.setText("Busy...");
                dAlg.execute();
                return true;
            }

            @Override
            protected void done() {
                List l = dAlg.getShortestPath(to);
                if (l
                        != null) {
                    route = new DrawableRoute(l);
                } else {
                    JOptionPane.showMessageDialog(null, "No Route",
                            "No Route Available", JOptionPane.ERROR_MESSAGE);
                    System.err.println("Route is null - No available route");
                }
                map1.setRoute(route);
                repaint();
                statusText.setText("Ready");
            }
        };
        worker.execute();
    }//GEN-LAST:event_btnNavigateMousePressed
    /**
     *
     * @param evt
     */
    private void map1MouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_map1MouseDragged
        offsetX = map1.getXOffset();
        offsetY = map1.getYOffset();
        offsetX += (1 / map1.getZoom() * (evt.getX() - dragStartX));
        offsetY += (1 / map1.getZoom() * (evt.getY() - dragStartY));
        map1.setOffset(offsetX, offsetY);
        repaint();
        dragStartX = evt.getX();
        dragStartY = evt.getY();
    }//GEN-LAST:event_map1MouseDragged
    /**
     *
     *
     * @param evt
     */
    private void map1MousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_map1MousePressed
        dragStartX = evt.getX();
        dragStartY = evt.getY();
    }//GEN-LAST:event_map1MousePressed
    /**
     *
     * @param evt
     */
    private void map1MouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_map1MouseWheelMoved
        if (evt.getWheelRotation() < 0) {
            map1.setZoom(map1.getZoom() * 1.5);
        } else {
            map1.setZoom(map1.getZoom() * 0.5);
        }
        repaint();
        System.out.println("Current zoom: " + map1.getZoom());
    }//GEN-LAST:event_map1MouseWheelMoved

    private void jMenu4MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jMenu4MouseClicked
        java.awt.EventQueue.invokeLater(new Runnable() { //Create an instance of the Load Window.
            @Override
            public void run() {
                try {
                    new Load(map1).setVisible(true);
                } catch (Exception ex) {
//                    ex.printStackTrace();
                }
            }
        });
    }//GEN-LAST:event_jMenu4MouseClicked

    private void jMenu3MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jMenu3MouseClicked
        java.awt.EventQueue.invokeLater(new Runnable() { //Create an instance of Save Window.
            @Override
            public void run() {
                try {
                    new Save(graph).setVisible(true);
                } catch (Exception ex) {
//                    ex.printStackTrace();
                }
            }
        });
    }//GEN-LAST:event_jMenu3MouseClicked

    /**
     * @param args the commandAlg line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;

                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(RouteViewGUI.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(RouteViewGUI.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(RouteViewGUI.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(RouteViewGUI.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new RouteViewGUI().setVisible(true);
                } catch (Exception ex) {
//                    ex.printStackTrace();
                }
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnNavigate;
    private javax.swing.JComboBox cmbPointA;
    private javax.swing.JComboBox cmbPointB;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenu jMenu4;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JLabel lblPointA;
    private javax.swing.JLabel lblPointB;
    private view.Map map1;
    private javax.swing.JPanel pnlButonTray;
    private javax.swing.JLabel statusText;
    // End of variables declaration//GEN-END:variables

}
